﻿using System;
using System.Data.SqlClient;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Modules._2DoTasks.Components.Entities;
using DotNetNuke.Modules._2DoTasks.Components.ExceptionHandling;
using DotNetNuke.Modules._2DoTasks.Components.Interfaces;
using DotNetNuke.Modules._2DoTasks.Data;

namespace DotNetNuke.Modules._2DoTasks.Components.Controllers
{
    /// <summary>
    /// Controller object with business logic for tasks
    /// </summary>
    public class TaskController : IRepository<Entities._Task, int>
    {
        private UnitOfWork _uof;

        #region IRepository<_Task> Members

        public TaskController(UnitOfWork uof)
        {
            _uof = uof;
        }

        /// <summary>
        /// Gets the task with the passed id
        /// </summary>
        /// <param name="taskId">the task id</param>
        /// <param name="additionalFields">not used in task entity</param>
        /// <returns>returns a task object</returns>
        public Entities._Task Get(int taskId, params object[] additionalFields)
        {
            return CBO.FillObject<Entities._Task>(DataProvider.Instance().GetTask(taskId, this._uof.PortalId, this._uof.CurrentUser.UserID));
        }

        /// <summary>
        /// Returns all tasks
        /// </summary>
        /// <returns>retuns list of tasks</returns>
        public System.Collections.Generic.List<Entities._Task> GetAll()
        {
            return CBO.FillCollection<Entities._Task>(DataProvider.Instance().GetAllTasks(this._uof.PortalId, this._uof.CurrentUser.UserID));
        }

        /// <summary>
        /// Returns all tasks, based on specific filter options
        /// </summary>
        /// <param name="assignedOptions">the assigned who for the tasks</param>
        /// <param name="filterAditionalOptions">additional filter options</param>
        /// <returns>return list of tasks, based on the passed options</returns>
        public System.Collections.Generic.List<Entities._Task> Find(
            SharedEnum.FilterAssigned assignedOptions,
            Nullable<SharedEnum.Task_FilterAditionalOptions> filterAditionalOptions,
            Nullable<int> projectId)
        {
            return CBO.FillCollection<Entities._Task>(DataProvider.Instance().
                FindTasks(this._uof.PortalId, this._uof.CurrentUser.UserID, assignedOptions, filterAditionalOptions, projectId));
        }

        /// <summary>
        /// Adds a new entity
        /// </summary>
        /// <param name="entity">entity to create</param>
        public void Add(Entities._Task entity)
        {
            try
            {
                entity.CreationUserId = this._uof.CurrentUser.UserID;
                entity.ModuleID = this._uof.ModuleId;
                entity.PortalId = this._uof.PortalId;

                entity.TaskId = DataProvider.Instance().Add(entity);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("fk_Tsk_ProjectId"))
                    throw new TaskValidationException("Project not found.",
                        SharedEnum.CrudState.Update,
                        (int)InsertStatus.PROJECTNOTFOUND);

                if (exc.Message.Contains("CREATORNOTMEMBER"))
                    throw new TaskValidationException("The task creation user is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)InsertStatus.CREATORNOTMEMBER);

                if (exc.Message.Contains("ASSIGNEDNOTMEMBER"))
                    throw new TaskValidationException("The task assigned user is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)InsertStatus.ASSIGNEDNOTMEMBER);

                if (exc.Message.Contains("INVALIDASSIGNEDUSER"))
                    throw new TaskValidationException("If the task doesn't belong to a project, than the assigned user must be null, or the task creator.",
                        SharedEnum.CrudState.Update,
                        (int)InsertStatus.INVALIDASSIGNEDUSER);

                throw exc;
            }
        }

        /// <summary>
        /// Updates a task
        /// </summary>
        /// <param name="entity">task to update</param>
        public void Update(Entities._Task entity)
        {
            try
            {
                entity.LastChangeUserId = this._uof.CurrentUser.UserID;
                entity.ModuleID = this._uof.ModuleId;
                entity.PortalId = this._uof.PortalId;

                DataProvider.Instance().Update(entity);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("fk_Tsk_ProjectId"))
                    throw new TaskValidationException("Project not found.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.PROJECTNOTFOUND);

                if (exc.Message.Contains("ONLYCREATORCANCHANGE"))
                    throw new TaskValidationException("Only the creation user can change this task.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.ONLYCREATORCANCHANGE);

                if (exc.Message.Contains("CANNOTSETEMPTYPROJECT"))
                    throw new TaskValidationException("Cannot remove task from project.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.CANNOTSETEMPTYPROJECT);

                if (exc.Message.Contains("CREATORNOTMEMBER"))
                    throw new TaskValidationException("The task creation user is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.CREATORNOTMEMBER);

                if (exc.Message.Contains("LASTCHANGEUSERNOTMEMBER"))
                    throw new TaskValidationException("The user changing the project is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.LASTCHANGEUSERNOTMEMBER);

                if (exc.Message.Contains("ASSIGNEDNOTMEMBER"))
                    throw new TaskValidationException("The assigned user is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.ASSIGNEDNOTMEMBER);

                if (exc.Message.Contains("INVALIDASSIGNEDUSER"))
                    throw new TaskValidationException("If the task doesn't belong to a project, than the assigned user must be null, or the task creator.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.INVALIDASSIGNEDUSER);

                throw exc;
            }
        }

        /// <summary>
        /// Changes teh task status
        /// </summary>
        /// <param name="entity">task to update</param>
        public void SetStatus(int taskId, SharedEnum.TaskStatus status, Nullable<DateTime> completionDate)
        {
            try
            {
                _Task task = new _Task
                {
                    TaskId = taskId,
                    LastChangeUserId = this._uof.CurrentUser.UserID,
                    TaskStatus = (short)status,
                    CompletionDate = completionDate
                };

                DataProvider.Instance().SetStatus(task);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("ONLYCREATORCANCHANGE"))
                    throw new TaskValidationException("Only the creation user can change this task.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.ONLYCREATORCANCHANGE);

                if (exc.Message.Contains("LASTCHANGEUSERNOTMEMBER"))
                    throw new TaskValidationException("The user changing the project is not a member of the project.",
                        SharedEnum.CrudState.Update,
                        (int)UpdateStatus.LASTCHANGEUSERNOTMEMBER);

                throw exc;
            }
        }

        /// <summary>
        /// Deletes an existing task
        /// </summary>
        /// <param name="entity">task to delete</param>
        public void Delete(_Task entity)
        {
            try
            {
                entity.ModuleID = this._uof.ModuleId;
                entity.PortalId = this._uof.PortalId;
                DataProvider.Instance().Delete(entity, this._uof.CurrentUser.UserID);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("ONLYCREATORCANDELETE"))
                    throw new TaskValidationException("Only the task creation user can delete.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.ONLYCREATORCANDELETE);

                if (exc.Message.Contains("CURRENTUSERNOTMEMBER"))
                    throw new TaskValidationException("User deleting is not a project member.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.CURRENTUSERNOTMEMBER);

                throw exc;
            }
        }

        #endregion IRepository<_Task> Members

        #region "Crud Enums"

        public enum InsertStatus
        {
            PROJECTNOTFOUND = -1,
            CREATORNOTMEMBER = -2,
            ASSIGNEDNOTMEMBER = -3,
            INVALIDASSIGNEDUSER = -4
        }

        public enum UpdateStatus
        {
            PROJECTNOTFOUND = -1,
            ONLYCREATORCANCHANGE = -2,
            CANNOTSETEMPTYPROJECT = -3,
            CREATORNOTMEMBER = -4,
            LASTCHANGEUSERNOTMEMBER = -5,
            ASSIGNEDNOTMEMBER = -6,
            INVALIDASSIGNEDUSER = -7
        }

        public enum DeleteStatus
        {
            ONLYCREATORCANDELETE = -1,
            CURRENTUSERNOTMEMBER = -2
        }

        #endregion "Crud Enums"
    }
}